﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using System.Configuration;

namespace GDoc.Domain
{
    /// <summary>
    /// Manages the Unity Containers
    /// </summary>
    public class Unity : IDisposable
    {
        private Dictionary<string, IUnityContainer> lookupTable;

        private string defaultContainer = "defaultContainer";
        private string azureContainer = "azureContainer";

        /// <summary>
        /// Get the default container
        /// </summary>
        /// <returns>The default container</returns>
        public IUnityContainer Container
        {
            get
            {
                return GetContainer(defaultContainer);
            }
        }

        /// <summary>
        /// Get the azure container
        /// </summary>
        /// <returns>The azure container</returns>
        public IUnityContainer AzureContainer
        {
            get
            {
                return GetContainer(azureContainer);
            }
        }

        /// <summary>
        /// Get a particular container by name
        /// </summary>
        /// <param name="containerName">Name of the container</param>
        /// <returns>Unity Container</returns>
        /// <exception cref="System.Configuration.ConfigurationErrorsException">
        /// This exception is thrown when the specified container is not found</exception>
        public IUnityContainer GetContainer(string containerName)
        {
            if (lookupTable.ContainsKey(containerName))
                return lookupTable[containerName];

            IUnityContainer container = new UnityContainer();

            UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");

            if (section == null || section.Containers[containerName] == null)
            {
                throw new ConfigurationErrorsException(string.Format("Unity configuration for '{0}' not found", containerName));
            }

            section.Configure(container, containerName);

            lookupTable[containerName] = container;

            return container;
        }

        /// <summary>
        /// Creates a new Unity object
        /// </summary>
        private Unity()
        {
            lookupTable = new Dictionary<string, IUnityContainer>();
        }

        /// <summary>
        /// Dispose the Unity class
        /// </summary>
        public void Dispose()
        {
            foreach (var container in lookupTable)
                container.Value.Dispose();

            lookupTable.Clear();
        }

        #region Singleton
        [ThreadStatic]
        private static volatile Unity instance = null;

        /// <summary>
        /// Singleton instance for the current thread.
        /// </summary>
        public static Unity Current
        {
            get
            {
                if (instance == null)
                    instance = new Unity();
                return instance;
            }
            protected set
            {
                instance = value;
            }
        }

        /// <summary>
        /// Dispose the current singleton instance
        /// </summary>
        public static void DisposeCurrent()
        {
            if (instance != null)
            {
                instance.Dispose();
                instance = null;
            }
        }
        #endregion Singleton
    }
}
